﻿Public Class frmCalibration

#Region "Properties"

    Friend Property Calibration As clsCalibration

#End Region

#Region "Private Variables"

    Private dgvEFDC As WRDB.Controls.DGVEditor
    Private IsEfdc As Boolean = False
    Private IsWasp As Boolean = False

    Const DEPTH_AVERAGED As String = "Depth-Independent"

#End Region

#Region "Form Events..."

    Public Sub New(Calib As clsCalibration)

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.

        Calibration = Calib

    End Sub

    Private Sub frmCalibration_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        Try
            GetWindowPos(REGAPP, Me)
            With Calibration

                cboTableMeas.Items.Clear()
                cboTableSim.Items.Clear()

                For Each tbl As clsTable In OpenTables
                    If tbl.TableType <> clsTable.enumTableType.Calibration Then
                        cboTableMeas.Items.Add(tbl.TableName)
                        cboTableSim.Items.Add(tbl.TableName)
                    End If
                Next

                If .tblMeasured IsNot Nothing Then cboTableMeas.Text = .tblMeasured.TableName
                If .tblSimulated IsNot Nothing Then cboTableSim.Text = .tblSimulated.TableName

                For Each s As String In .dictBranches.Keys
                    cboBranch.Items.Add(s)
                Next
                cboBranch.SelectedIndex = IIf(cboBranch.Items.Count = 0, -1, 0)

                For i As Integer = 1 To 4
                    Dim chk As CheckedListBox = Choose(i, chkStationsMeas, chkParmsMeas, chkStationsSim, chkParmsSim)
                    chk.CheckOnClick = True
                    chk.SelectionMode = SelectionMode.One
                    chk.ClearSelected()
                Next

                dgvEFDC = New WRDB.Controls.DGVEditor(dgEFDC)
                dgvEFDC.SetHeadings("I~J~DX~DY")
                For c As Integer = 0 To 3
                    With dgEFDC.Columns(c)
                        .FillWeight = 25
                        .AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
                    End With
                Next

                cboEfdcBranchType.Items.AddRange(New String() {"Longitudinal", "Lateral"})
                cboEfdcBranchType.SelectedIndex = 0

            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub frmCalibration_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        SaveWindowPos(REGAPP, Me)
    End Sub

#End Region

#Region "Control Events..."

    Private Sub btnOK_Click(sender As Object, e As System.EventArgs) Handles btnOK.Click
        With Calibration
            .MinDate = dtMinDate.Value
            .MaxDate = dtMaxDate.Value
        End With
        If cboBranch.Items.Count = 0 Or
           lstStationsAgg.Items.Count = 0 Or
           lstParmsAgg.Items.Count = 0 Or
           cboTableMeas.SelectedIndex = -1 Or
           cboTableSim.SelectedIndex = -1 Then
            WarningMsg("You must specify one or more or the following:\n\n\t\b Branch\n\t\b Aggregate Station\n\t\b Aggregate Parameter\n\t\b Measured Data Table\n\t\b Simulated Data Table")
            Exit Sub
        End If

        DialogResult = Windows.Forms.DialogResult.OK
        Close()
    End Sub

    Private Sub btnCancel_Click(sender As Object, e As System.EventArgs) Handles btnCancel.Click
        Close()
    End Sub

    Private Sub btnNewBranch_Click(sender As Object, e As System.EventArgs) Handles btnNewBranch.Click
        With Calibration
            Dim s As String = InputBox("Enter name of new branch:")
            If s <> "" Then
                s = s.Replace(";", ":") 'cannot have semicolons--used as delimiter in settings
                If .dictBranches.ContainsKey(s) Then WarningMsg("Branch name already exists; please specify unique name.") : Exit Sub

                .dictBranches.Add(s, New clsBranch(s))

                cboBranch.Items.Clear()
                For Each b As String In .dictBranches.Keys
                    cboBranch.Items.Add(b)
                Next
                cboBranch.Text = s
            End If
        End With
    End Sub

    Private Sub btnDeleteBranch_Click(sender As System.Object, e As System.EventArgs) Handles btnDeleteBranch.Click
        If cboBranch.SelectedIndex = -1 Then Exit Sub
        With cboBranch
            Calibration.dictBranches.Remove(.Text)
            .Items.Remove(.Text)
            .SelectedIndex = IIf(.Items.Count = 0, -1, 0)
        End With
    End Sub

    Private Sub cboBranch_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles cboBranch.SelectedIndexChanged
        FillStationList()
        With Calibration
            cboEFDCWeightingParm.Text = .WeightingParameter
            If .MinDate <> Now.Date Then dtMinDate.Value = .MinDate
            If .MaxDate <> Now.Date Then dtMaxDate.Value = .MaxDate
        End With
    End Sub

    ''' <summary>
    ''' Selected measured data table has changed; fill stations and parameter list boxes
    ''' </summary>
    Private Sub cboTableMeas_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles cboTableMeas.SelectedIndexChanged
        For Each tbl As clsTable In OpenTables
            If tbl.TableName = cboTableMeas.Text Then
                Calibration.tblMeasured = tbl
                chkStationsMeas.Items.Clear()
                chkStationsMeas.Items.AddRange(tbl.GetStationList("").ToArray)
                chkParmsMeas.Items.Clear()
                chkParmsMeas.Items.AddRange(tbl.GetPCodeList("").ToArray)
                Dim MinDate, MaxDate As Date
                If tbl.GetDateRange(MinDate, MaxDate) Then
                    dtMinDate.Value = MinDate
                    dtMaxDate.Value = MaxDate
                End If
                Dim MinDepth, MaxDepth As Double
                If tbl.GetDepthRange(MinDepth, MaxDepth) AndAlso MinDepth <> Double.MinValue AndAlso MaxDepth <> Double.MaxValue Then
                    txtMinDepth.Text = MinDepth
                    txtMaxDepth.Text = MaxDepth
                    If ActiveParameter() IsNot Nothing Then
                        ActiveParameter.MinDepth = MinDepth
                        ActiveParameter.MaxDepth = MaxDepth
                    End If
                    grpDepth.Enabled = True
                Else
                    grpDepth.Enabled = False
                End If
                Exit For
            End If
        Next
        UpdateLabels()
    End Sub

    ''' <summary>
    ''' Selected measured data table has changed; fill stations and parameter list boxes; also detect if is EFDC BMD file and fill EFDC tab
    ''' </summary>
    Private Sub cboTableSim_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles cboTableSim.SelectedIndexChanged
        Try
            For Each tbl As clsTable In OpenTables
                If tbl.TableName = cboTableSim.Text Then
                    Calibration.tblSimulated = tbl

                    chkStationsSim.Items.Clear()
                    chkStationsSim.Items.AddRange(tbl.GetStationList("").ToArray)
                    chkParmsSim.Items.Clear()
                    chkParmsSim.Items.AddRange(tbl.GetPCodeList("").ToArray)

                    'see if is EFDC or Wasp file...
                    Dim lstI As New Generic.List(Of Integer)
                    Dim lstJ As New Generic.List(Of Integer)
                    Dim lstK As New Generic.List(Of String)
                    Dim lstParm As New Generic.List(Of String)

                    For i As Integer = 0 To chkStationsSim.Items.Count - 1
                        Dim ii As Integer, jj As Integer
                        If TryGetEfdcIJ(i, ii, jj) Then
                            If Not lstI.Contains(ii) Then lstI.Add(ii)
                            If Not lstJ.Contains(jj) Then lstJ.Add(jj)
                        End If
                    Next

                    If lstI.Count > 0 And lstJ.Count > 0 Then
                        For i As Integer = 0 To chkParmsSim.Items.Count - 1
                            Dim depth As String = "", parm As String = ""
                            If TryGetEfdcDepth(i, depth, parm) Then
                                If Not lstK.Contains(depth) Then lstK.Add(depth)
                            End If
                            If Not lstParm.Contains(parm) Then lstParm.Add(parm)
                        Next
                        If lstK.Count > 1 And lstParm.Count > 0 Then IsEfdc = True
                    End If

                    If Not IsEfdc Then
                        lstI.Clear()
                        lstJ.Clear()
                        lstK.Clear()
                        For i As Integer = 0 To chkStationsSim.Items.Count - 1
                            Dim ii, jj, kk As Integer
                            If TryGetWaspIJK(i, ii, jj, kk) Then
                                If Not lstI.Contains(ii) Then lstI.Add(ii)
                                If Not lstJ.Contains(jj) Then lstJ.Add(jj)
                                If Not lstK.Contains("K=" & kk) Then lstK.Add("K=" & kk)
                            End If
                        Next
                        lstK.Sort()

                        If lstI.Count > 0 And lstJ.Count > 0 And lstK.Count > 0 Then
                            For i As Integer = 0 To chkParmsSim.Items.Count - 1
                                Dim parm As String = chkParmsSim.Items(i)
                                If Not lstParm.Contains(parm) Then
                                    lstParm.Add(parm)
                                End If
                            Next
                            lstParm.Sort()
                            If lstParm.Count > 0 Then IsWasp = True
                        End If
                    End If

                    If IsEfdc Or IsWasp Then 'really is an EFDC file; fill controls on that tab

                        lstI.Sort()

                        cboEFDCMinI.Items.Clear()
                        cboEFDCMaxI.Items.Clear()
                        For Each i As Integer In lstI
                            cboEFDCMinI.Items.Add(i)
                            cboEFDCMaxI.Items.Add(i)
                        Next

                        lstJ.Sort()
                        cboEFDCMinJ.Items.Clear()
                        cboEFDCMaxJ.Items.Clear()
                        For Each j As Integer In lstJ
                            cboEFDCMinJ.Items.Add(j)
                            cboEFDCMaxJ.Items.Add(j)
                        Next

                        chkEFDCDepth.Items.Clear()
                        chkEFDCDepth.Items.AddRange(lstK.ToArray)

                        chkEFDCParms.Items.Clear()
                        chkEFDCParms.Items.AddRange(lstParm.ToArray)

                        cboEFDCWeightingParm.Items.Clear()
                        cboEFDCWeightingParm.Items.AddRange(lstParm.ToArray)

                        'now try to set to previously saved values

                        UpdateChecklists()
                        cboEFDCWeightingParm.Text = Calibration.WeightingParameter

                        'show the EFDC tab control
                        tblSimGeneral.Visible = False
                        tabSim.Visible = True
                        tblSim.RowStyles(1).Height = 0
                        tblSim.RowStyles(2).Height = 100
                    Else
                        'show the general list boxes only
                        tblSimGeneral.Visible = True
                        tabSim.Visible = False
                        tblSim.RowStyles(1).Height = 100
                        tblSim.RowStyles(2).Height = 0
                    End If

                    Dim MinDate, MaxDate As Date
                    If tbl.GetDateRange(MinDate, MaxDate) Then
                        dtMinDate.Value = MinDate
                        dtMaxDate.Value = MaxDate
                    End If

                    Exit For
                End If
            Next
            UpdateLabels()
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    ''' <summary>
    ''' Checked item has changed; resave all checked items to internal structure
    ''' </summary>
    Private Sub chk_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles chkStationsMeas.SelectedIndexChanged, chkParmsMeas.SelectedIndexChanged, chkStationsSim.SelectedIndexChanged, chkParmsSim.SelectedIndexChanged
        If sender.SelectedIndex = -1 Then Exit Sub
        If sender Is chkParmsMeas AndAlso lstParmsAgg.SelectedIndex <> -1 Then 'no more than one box checked (unless there are no stations & pcodes so can create many by clicking link)
            ClearCheckboxes(chkParmsMeas)
            chkParmsMeas.SetItemChecked(chkParmsMeas.SelectedIndex, True)
        End If
        SaveChecklists()
        If sender Is chkParmsMeas Or sender Is chkParmsSim Then
            Dim aggParm As String = lstParmsAgg.Text
            Dim newParm As String = CType(sender, CheckedListBox).Text
            Dim lst As Generic.List(Of String) = Nothing

            'may have added a new agg parameter for which parameters haven't been selected; if that is the case, for all matching empty agg parameters select this same parameter
            For Each sta As clsStation In ActiveBranch.dictStations.Values
                If sta.dictParameters.ContainsKey(aggParm) Then
                    With sta.dictParameters(aggParm)
                        If sender Is chkParmsMeas Then lst = .lstParametersMeas Else lst = .lstParametersSim
                        If lst.Count = 0 Then lst.Add(newParm)
                    End With
                End If
            Next
        End If
        If sender Is chkStationsSim Then
            'assign same station mapping as this for all other unassigned parameters
            For Each parm As clsParameter In ActiveStation.dictParameters.Values
                If parm.Name <> lstParmsAgg.Text AndAlso parm.lstStationsSim.Count = 0 Then
                    Dim lst As Generic.List(Of String) = ActiveStation.dictParameters(lstParmsAgg.Text).lstStationsSim
                    parm.lstStationsSim.Clear()
                    For i As Integer = 0 To lst.Count - 1
                        parm.lstStationsSim.Add(lst(i))
                    Next
                End If
            Next
        End If
        sender.SelectedItems.Clear()
    End Sub

    ''' <summary>
    ''' Create new agg stations comprised of all check measured stations and pcode
    ''' </summary>
    Private Sub lnkBuildMeas_LinkClicked(sender As System.Object, e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles lnkBuildMeas.LinkClicked
        BuildStations()
    End Sub

    Private Sub BuildStations()
        Try
            If cboBranch.SelectedIndex = -1 Then Exit Sub
            For Each s As String In chkStationsMeas.CheckedItems
                s = StringSplit(s, " - ")(0)
                With ActiveBranch.dictStations
                    Dim sta As clsStation
                    If .ContainsKey(s) Then
                        sta = .Item(s)
                    Else
                        sta = New clsStation(s)
                        'todo: also add other info from stations table (river mile)
                        sta.Length = 0
                        .Add(s, sta)
                    End If
                    For Each p As String In chkParmsMeas.CheckedItems
                        With sta.dictParameters
                            Dim parm As clsParameter
                            If .ContainsKey(p) Then
                                parm = .Item(p)
                            Else
                                parm = New clsParameter(p)
                                .Add(p, parm)
                            End If
                            With parm.lstStationsMeas
                                If Not .Contains(s) Then .Add(s)
                            End With
                            With parm.lstParametersMeas
                                If Not .Contains(p) Then .Add(p)
                            End With
                        End With
                    Next
                End With
            Next

            FillStationList()

        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    ''' <summary>
    ''' New agg parameter selected; check appropriate boxes
    ''' </summary>
    Private Sub lstParmsAgg_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles lstParmsAgg.SelectedIndexChanged
        Try
            UpdateChecklists()
            mnuDeleteParm.Enabled = lstParmsAgg.SelectedIndex <> -1
            mnuDeleteParmAll.Enabled = lstParmsAgg.SelectedIndex <> -1
            tblSimGeneral.Enabled = lstParmsAgg.SelectedIndex <> -1
            tblSimEFDC.Enabled = lstParmsAgg.SelectedIndex <> -1
            If ActiveParameter() IsNot Nothing AndAlso ActiveParameter.MinDepth <> Double.MinValue Then txtMinDepth.Text = ActiveParameter.MinDepth Else txtMinDepth.Text = ""
            If ActiveParameter() IsNot Nothing AndAlso ActiveParameter.MaxDepth <> Double.MaxValue Then txtMaxDepth.Text = ActiveParameter.MaxDepth Else txtMaxDepth.Text = ""
            UpdateLabels()
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub lstStationsAgg_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles lstStationsAgg.SelectedIndexChanged
        Try
            If cboBranch.SelectedIndex = -1 Then Exit Sub
            Dim savedParm As String = lstParmsAgg.Text
            lstParmsAgg.Items.Clear()
            For i As Integer = 1 To 4
                ClearCheckboxes(Choose(i, chkStationsMeas, chkParmsMeas, chkStationsSim, chkParmsMeas))
            Next
            If lstStationsAgg.SelectedIndex = -1 Then Exit Sub
            With ActiveStation()
                txtLength.Text = .Length
                For Each s As String In .dictParameters.Keys
                    lstParmsAgg.Items.Add(s)
                Next
                If lstParmsAgg.Items.Contains(savedParm) Then
                    lstParmsAgg.Text = savedParm
                Else
                    lstParmsAgg.SelectedIndex = IIf(lstParmsAgg.Items.Count = 0, -1, 0)
                End If
            End With
            txtLength.Enabled = lstStationsAgg.SelectedIndex <> -1
            mnuDeleteSta.Enabled = lstStationsAgg.SelectedIndex <> -1
            mnuDeleteStaAll.Enabled = lstStationsAgg.SelectedIndex <> -1
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    ''' <summary>
    ''' Context menu is shortcut to clicking button
    ''' </summary>
    Private Sub mnuStaList_ItemClicked(sender As Object, e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuStaList.ItemClicked
        If e.ClickedItem Is mnuNewSta Then
            NewStation()
        ElseIf e.ClickedItem Is mnuNewStaChecked Then
            BuildStations()
        ElseIf e.ClickedItem Is mnuDeleteSta Then
            DeleteStation(False)
        ElseIf e.ClickedItem Is mnuDeleteStaAll Then
            DeleteStation(True)
        End If
    End Sub

    ''' <summary>
    ''' Context menu is shortcut to clicking button
    ''' </summary>
    Private Sub mnuParmList_ItemClicked(sender As Object, e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuParmList.ItemClicked
        If e.ClickedItem Is mnuNewParm Then
            NewParm(False)
        ElseIf e.ClickedItem Is mnuNewParmAll Then
            NewParm(True)
        ElseIf e.ClickedItem Is mnuDeleteParm Then
            DeleteParm(False)
        ElseIf e.ClickedItem Is mnuDeleteParmAll Then
            DeleteParm(True)
        ElseIf e.ClickedItem Is mnuAssignParm Then
            AssignParm()
        End If
    End Sub

    Private Sub NewStation()
        If cboBranch.SelectedIndex = -1 Then Exit Sub
        Dim s As String = InputBox("Enter name of new stations:")
        If s <> "" Then
            s = s.ToUpper
            s = s.Replace(";", ":") 'cannot have semicolons--used as delimiter in settings
            If ActiveBranch.dictStations.ContainsKey(s) Then WarningMsg("Station name already exists; please specify unique name.") : Exit Sub

            Dim newSta As New clsStation(s)

            'add all agg parms for selected station 
            If ActiveStation() IsNot Nothing Then
                For Each parm As clsParameter In ActiveStation.dictParameters.Values
                    newSta.dictParameters.Add(parm.Name, parm.Clone)
                    newSta.dictParameters(parm.Name).lstStationsMeas.Clear()
                    newSta.dictParameters(parm.Name).lstStationsSim.Clear()
                Next
            End If

            ActiveBranch.dictStations.Add(s, newSta)

            lstStationsAgg.Items.Clear()
            For Each b As String In ActiveBranch.dictStations.Keys
                lstStationsAgg.Items.Add(b)
            Next
            lstStationsAgg.Text = s
        End If
    End Sub

    Private Sub DeleteStation(AllStations As Boolean)
        If cboBranch.SelectedIndex = -1 Then Exit Sub
        With lstStationsAgg
            If AllStations Then
                ActiveBranch.dictStations.Clear()
                .Items.Clear()
                lstParmsAgg.Items.Clear()
            Else
                ActiveBranch.dictStations.Remove(.Text)
                .Items.Remove(.Text)
            End If
            .SelectedIndex = IIf(.Items.Count = 0, -1, 0)
        End With
    End Sub

    Private Sub NewParm(AllStations As Boolean)
        Try
            With Calibration
                Dim parmName As String = InputBox("Enter name of new parameter:")
                If parmName <> "" Then
                    parmName = parmName.ToUpper
                    parmName = parmName.Replace(";", ":") 'cannot have semicolons--used as delimiter in settings
                    Dim parmAgg As New clsParameter(parmName)
                    If ActiveStation.dictParameters.ContainsKey(parmName) Then WarningMsg("Parameter name already exists; please specify unique name.") : Exit Sub

                    'try to add all meas and sim parameters that have identical names to that of new agg parameter
                    If .tblMeasured IsNot Nothing Then
                        For Each p As String In .tblMeasured.GetPCodeList("")
                            If parmName.ToUpper = p.ToUpper And Not parmAgg.lstParametersMeas.Contains(p) Then parmAgg.lstParametersMeas.Add(p)
                        Next
                    End If
                    If .tblSimulated IsNot Nothing Then
                        For Each p As String In .tblSimulated.GetPCodeList("")
                            If p.ToUpper.EndsWith(parmName.ToUpper) And Not parmAgg.lstParametersSim.Contains(p) Then parmAgg.lstParametersSim.Add(p)
                        Next
                    End If

                    If AllStations Then
                        'add this new agg parameter for all agg stations (if not already there)
                        For Each staAgg As clsStation In ActiveBranch.dictStations.Values
                            If Not staAgg.dictParameters.ContainsKey(parmName) Then staAgg.dictParameters.Add(parmName, New clsParameter(parmName))

                            'also assign measured and simulated stations associated with currently selected agg parameter to new agg parameter

                            Dim selParm As clsParameter = Nothing
                            If staAgg.dictParameters.TryGetValue(lstParmsAgg.Text, selParm) Then
                                Dim newParm As clsParameter = Nothing
                                If staAgg.dictParameters.TryGetValue(parmName, newParm) Then
                                    newParm.lstParametersMeas.AddRange(parmAgg.lstParametersMeas)
                                    newParm.lstParametersSim.AddRange(parmAgg.lstParametersSim)

                                    For Each sta As String In selParm.lstStationsMeas
                                        If Not newParm.lstStationsMeas.Contains(sta) Then newParm.lstStationsMeas.Add(sta)
                                    Next
                                    For Each sta As String In selParm.lstStationsSim
                                        If Not newParm.lstStationsSim.Contains(sta) Then newParm.lstStationsSim.Add(sta)
                                    Next
                                End If
                            End If
                        Next
                    Else
                        ActiveStation.dictParameters.Add(parmName, parmAgg)

                        'if a parameter is currently selected, copy assigned stations from there
                        If ActiveParameter() IsNot Nothing Then
                            parmAgg.lstStationsMeas.AddRange(ActiveParameter.lstStationsMeas)
                            parmAgg.lstStationsSim.AddRange(ActiveParameter.lstStationsSim)
                        End If

                        'look for other agg stations that have this same parameter; if found assign same parameter names
                        For Each staAgg As clsStation In ActiveBranch.dictStations.Values
                            If staAgg.Name <> ActiveStation.Name AndAlso staAgg.dictParameters.ContainsKey(parmName) Then
                                For Each p As String In staAgg.dictParameters(parmName).lstParametersMeas
                                    ActiveStation.dictParameters(parmName).lstParametersMeas.Add(p)
                                Next
                                For Each p As String In staAgg.dictParameters(parmName).lstParametersSim
                                    ActiveStation.dictParameters(parmName).lstParametersSim.Add(p)
                                Next
                            End If
                        Next
                    End If

                    'refill list
                    lstParmsAgg.Items.Clear()
                    For Each b As String In ActiveStation.dictParameters.Keys
                        lstParmsAgg.Items.Add(b)
                    Next
                    lstParmsAgg.Text = parmName
                End If
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub DeleteParm(AllStations As Boolean)
        With lstParmsAgg
            If AllStations Then
                For Each sta As clsStation In ActiveBranch.dictStations.Values
                    If sta.dictParameters.ContainsKey(.Text) Then sta.dictParameters.Remove(.Text)
                Next
            Else
                ActiveStation.dictParameters.Remove(.Text)
            End If
            '.SelectedIndex = -1
            .Items.Remove(.Text)
            .SelectedIndex = IIf(.Items.Count = 0, -1, 0)
        End With
    End Sub

    Private Sub AssignParm()
        Dim lstMeas As New Generic.List(Of String)
        lstMeas.AddRange(ActiveParameter.lstParametersMeas)
        Dim lstSim As New Generic.List(Of String)
        lstSim.AddRange(ActiveParameter.lstParametersSim)
        For Each sta As clsStation In ActiveBranch.dictStations.Values
            If sta.dictParameters.ContainsKey(ActiveParameter.Name) Then
                With sta.dictParameters(ActiveParameter.Name)
                    'If .lstParametersMeas.Count = 0 Then .lstParametersMeas.AddRange(ActiveParameter.lstParametersMeas)
                    'If .lstParametersSim.Count = 0 Then .lstParametersSim.AddRange(ActiveParameter.lstParametersSim)
                    .lstParametersMeas.Clear()
                    .lstParametersMeas.AddRange(lstMeas)
                    .lstParametersSim.Clear()
                    .lstParametersSim.AddRange(lstSim)
                End With
            End If
        Next
    End Sub

    ''' <summary>
    ''' Check all or none
    ''' </summary>
    Private Sub mnuChkList_ItemClicked(sender As Object, e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles mnuChkList.ItemClicked
        Dim chk As CheckedListBox = CType(sender, ContextMenuStrip).SourceControl
        With chk
            If .Items.Count > 1 Then
                For i As Integer = IIf(chk Is chkEFDCDepth And IsEfdc, 1, 0) To .Items.Count - 1 'if check all for EFDC depths, skip the first item
                    .SetItemChecked(i, e.ClickedItem Is mnuCheckAll)
                Next
                SaveChecklists()
            End If
        End With
    End Sub

    Private Sub txtLength_Validated(sender As Object, e As System.EventArgs) Handles txtLength.Validated
        ActiveStation.Length = Val(txtLength.Text)
    End Sub
#End Region

#Region "EFDC Control Events..."


    Private Sub btnEfdcBuildBranches_Click(sender As Object, e As System.EventArgs) Handles btnEfdcBuildBranches.Click
        Try
            Dim IsLongitudinal As Boolean = cboEfdcBranchType.SelectedIndex = 0
            Dim arBranchList() As String = txtEfdcIndices.Text.Split(",")

            Dim arParms() As String = txtEfdcParmList.Text.Split(",")

            'get range of indices
            Dim minI, maxI, minJ, maxJ As Integer
            With cboEFDCMinI
                minI = .Items(0)
                maxI = .Items(.Items.Count - 1)
            End With
            With cboEFDCMinJ
                minJ = .Items(0)
                maxJ = .Items(.Items.Count - 1)
            End With

            'read grid
            Dim IsGridDefined As Boolean = False
            Dim arGridValues(0 To cboEFDCMinI.Items(cboEFDCMinI.Items.Count - 1), 0 To cboEFDCMinJ.Items(cboEFDCMinJ.Items.Count - 1)) As PointF
            With dgEFDC
                For r As Integer = 0 To .RowCount - 1
                    If TestNull(.Item(0, r).Value, "") <> "" Then
                        Dim i As Integer = TestNull(.Item(0, r).Value, 0)
                        Dim j As Integer = TestNull(.Item(1, r).Value, 0)
                        Dim dx As Double = TestNull(.Item(2, r).Value, 0.0)
                        Dim dy As Double = TestNull(.Item(3, r).Value, 0.0)
                        If i >= 0 And i <= arGridValues.GetUpperBound(0) And j >= 0 And j <= arGridValues.GetUpperBound(1) Then
                            arGridValues(i, j) = New PointF(dx, dy)
                        End If
                    End If
                Next
            End With

            'form branches
            For Each s2 As String In arBranchList
                Dim minIndex As Integer = 0, maxIndex As Integer = 0
                If s2.Trim.ToUpper = "ALL" Then
                    minIndex = IIf(IsLongitudinal, minI, minJ)
                    maxIndex = IIf(IsLongitudinal, maxI, maxJ)
                ElseIf s2.Contains("-") Then
                    minIndex = Val(s2.Split("-")(0))
                    maxIndex = Val(s2.Split("-")(1))
                Else
                    minIndex = Val(s2)
                    maxIndex = Val(s2)
                End If
                For b As Integer = minIndex To maxIndex
                    Dim branch As New clsBranch(String.Format("{0} Profile ({1}={2})", IIf(IsLongitudinal, "Longitudinal", "Lateral"), IIf(IsLongitudinal, "J", "I"), b))
                    For c As Integer = IIf(IsLongitudinal, minI, minJ) To IIf(IsLongitudinal, maxI, maxJ)
                        Dim station As New clsStation("")
                        station.Length = 0
                        If IsLongitudinal Then
                            station.Name = String.Format("I={0}, J={1}", c, b)
                            For i As Integer = 0 To c - 1
                                If arGridValues(i, b) <> PointF.Empty Then station.Length += arGridValues(i, b).X
                            Next
                        Else
                            station.Name = String.Format("I={0}, J={1}", b, c)
                            For j As Integer = 0 To c - 1
                                If arGridValues(b, j) <> PointF.Empty Then station.Length += arGridValues(b, j).Y
                            Next
                        End If
                        For Each p As String In arParms
                            Dim parm As New clsParameter(p.Trim.ToUpper)
                            Dim index As Integer = -1
                            If (IsLongitudinal AndAlso TryGetEfdcStationIndex(c, b, index)) OrElse TryGetEfdcStationIndex(b, c, index) Then
                                parm.lstStationsSim.Add(chkStationsSim.Items(index)) 'will have to add parameters later
                                station.dictParameters.Add(parm.Name, parm)
                            End If
                        Next
                        If station.dictParameters.Count > 0 Then branch.dictStations.Add(station.Name, station)
                    Next
                    If branch.dictStations.Count > 0 Then
                        If Calibration.dictBranches.ContainsKey(branch.Name) Then
                            Calibration.dictBranches(branch.Name) = branch
                        Else
                            Calibration.dictBranches.Add(branch.Name, branch)
                        End If
                    End If
                Next
            Next

            cboBranch.Items.Clear()
            For Each b As String In Calibration.dictBranches.Keys
                cboBranch.Items.Add(b)
            Next
            cboBranch.SelectedIndex = IIf(cboBranch.Items.Count = 0, -1, 0)

            WarningMsg("New branches and stations have been created as requested. You must now manually assign EFDC depths and parameters to each aggregate station and parameter. The ""Set for all aggregate stations"" link can be used to simplify the process after setting the desired depths and parameters for the first station.")
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Sub cboEfdcBranchType_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles cboEfdcBranchType.SelectedIndexChanged
        If cboEfdcBranchType.SelectedIndex = 0 Then
            lblEfdcIndices.Text = "List of desired J values:"
        Else
            lblEfdcIndices.Text = "List of desired I values:"
        End If
    End Sub

    ''' <summary>
    ''' I,J index ranges were changes; set appropriate check boxes in BMD stations list for all parameters associated with this agg station
    ''' </summary>
    Private Sub cboEFDC_SelectedIndexCommitted(sender As Object, e As System.EventArgs) Handles cboEFDCMinI.SelectionChangeCommitted, cboEFDCMaxI.SelectionChangeCommitted, cboEFDCMinJ.SelectionChangeCommitted, cboEFDCMaxJ.SelectionChangeCommitted
        GetCheckedStations()
    End Sub

    Private Sub GetCheckedStations()
        ClearCheckboxes(chkStationsSim)

        'don't let the max be less than the min

        If Val(cboEFDCMinI.Text) > Val(cboEFDCMaxI.Text) Or cboEFDCMaxI.Text = "" Then cboEFDCMaxI.Text = cboEFDCMinI.Text
        If Val(cboEFDCMinJ.Text) > Val(cboEFDCMaxJ.Text) Or cboEFDCMaxJ.Text = "" Then cboEFDCMaxJ.Text = cboEFDCMinJ.Text

        If ActiveParameter() Is Nothing Then Exit Sub

        ActiveParameter.lstStationsSim.Clear()

        'if i,j ranges are all set, then find all the BMD stations that match the range

        If cboEFDCMinI.SelectedIndex <> -1 AndAlso cboEFDCMaxI.SelectedIndex <> -1 AndAlso cboEFDCMinJ.SelectedIndex <> -1 AndAlso cboEFDCMaxJ.SelectedIndex <> -1 Then
            For Each parm As clsParameter In ActiveStation.dictParameters.Values
                parm.lstStationsSim.Clear()
                For i As Integer = cboEFDCMinI.Text To cboEFDCMaxI.Text
                    For j As Integer = cboEFDCMinJ.Text To cboEFDCMaxJ.Text
                        Dim staname As String = ""
                        If IsEfdc Then
                            If TryGetEfdcStationName(i, j, staname) Then
                                staname = StringSplit(staname, " - ")(0) 'strip off node number
                                If Not parm.lstStationsSim.Contains(staname) Then parm.lstStationsSim.Add(staname)
                            End If
                        ElseIf IsWasp Then
                            For k As Integer = 0 To chkEFDCDepth.CheckedItems.Count - 1
                                If TryGetWaspStationName(i, j, CStr(chkEFDCDepth.CheckedItems(k)).Replace("K=", ""), staname) Then
                                    staname = StringSplit(staname, " - ")(0) 'strip off node number
                                    If Not parm.lstStationsSim.Contains(staname) Then parm.lstStationsSim.Add(staname)
                                End If
                            Next
                        End If
                    Next
                Next
            Next
        End If
        UpdateLabels()
    End Sub

    ''' <summary>
    ''' Note that BMD file doesnt necessarily contain all possible I,J combinations in ranges; to make it easier, when I changes, reset available J lists
    ''' </summary>
    Private Sub cboEFDC_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles cboEFDCMinI.SelectedIndexChanged, cboEFDCMaxI.SelectedIndexChanged
        If cboEFDCMinI.SelectedIndex <> -1 And cboEFDCMaxI.SelectedIndex <> -1 Then
            Dim IMin As Integer = cboEFDCMinI.Text, IMax As Integer = cboEFDCMaxI.Text
            Dim lstJ As New Generic.List(Of Integer)
            For i As Integer = 0 To chkStationsSim.Items.Count - 1
                Dim ii, jj, kk As Integer
                If IIf(IsEfdc, TryGetEfdcIJ(i, ii, jj), TryGetWaspIJK(i, ii, jj, kk)) AndAlso ii >= IMin AndAlso ii <= IMax AndAlso Not lstJ.Contains(jj) AndAlso Not lstJ.Contains(jj) Then
                    lstJ.Add(jj)
                End If
            Next
            lstJ.Sort()

            For i As Integer = 1 To 2
                Dim cbo As ComboBox = Choose(i, cboEFDCMinJ, cboEFDCMaxJ)
                Dim LastJ As String = cbo.Text
                cbo.Items.Clear()
                For Each j As Integer In lstJ
                    cbo.Items.Add(j)
                Next
                'try to set to previous value used; otherwise to first in list
                If cbo.Items.Contains(LastJ) Then
                    cbo.Text = LastJ
                ElseIf cbo.Items.Count = 0 Then
                    cbo.SelectedIndex = -1
                Else
                    cbo.SelectedIndex = 0
                End If
            Next
        End If
    End Sub

    Private Sub cboEFDCWeightingParm_SelectionChangeCommitted(sender As Object, e As System.EventArgs) Handles cboEFDCWeightingParm.SelectionChangeCommitted
        If sender.SelectedIndex = -1 Then Exit Sub
        Calibration.WeightingParameter = cboEFDCWeightingParm.Text
    End Sub

    Private Sub chkEFDCDepth_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles chkEFDCDepth.SelectedIndexChanged
        With chkEFDCDepth
            If .SelectedIndex = -1 Then Exit Sub

            If IsEfdc Then
                'if check Depth-Averaged, clear all other checkboxes and uncheck any non-depth-averaged parms in parm list
                If .SelectedIndex = 0 Then
                    For i As Integer = 1 To .Items.Count - 1
                        .SetItemChecked(i, False)
                    Next
                    ClearCheckboxes(chkEFDCParms)
                Else
                    .SetItemChecked(0, False)
                    If .CheckedItems.Count < 1 Then ClearCheckboxes(chkEFDCParms)
                End If
            ElseIf IsWasp Then
                GetCheckedStations()
                Exit Sub
            End If

            SaveChecklists()
            .SelectedItems.Clear()
        End With
    End Sub

    Private Sub chkEFDCParms_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles chkEFDCParms.SelectedIndexChanged
        If sender.SelectedIndex = -1 Then Exit Sub
        'no more than one box checked
        ClearCheckboxes(chkEFDCParms)
        chkEFDCParms.SetItemChecked(chkEFDCParms.SelectedIndex, True)
        SaveChecklists()
        sender.SelectedItems.Clear()
    End Sub

    ''' <summary>
    ''' Assuming you've set up desired depth and pcode mapping properly, assign this mapping to all other EFDC stations
    ''' </summary>
    Private Sub lnkEfdcBuildParmSim_LinkClicked(sender As System.Object, e As System.Windows.Forms.LinkLabelLinkClickedEventArgs)
        For Each sta As clsStation In ActiveBranch.dictStations.Values
            For Each parm As clsParameter In sta.dictParameters.Values
                With parm.lstParametersSim
                    For Each s As String In ActiveParameter.lstParametersSim
                        If Not .Contains(s) Then .Add(s)
                    Next
                End With
            Next
        Next
    End Sub

    Private Sub txtEfdcParmList_Validated(sender As Object, e As System.EventArgs) Handles txtEfdcParmList.Validated
        txtEfdcParmList.Text = txtEfdcParmList.Text.ToUpper
    End Sub

#End Region

#Region "EFDC Helper Routines..."


    ''' <summary>
    ''' Given item in parameter chklistbox, parse parameter and return depth and parameter name value if possible
    ''' Note: if depth cannot be parsed, will still return full parameter name
    ''' </summary>
    ''' <param name="index">Index value</param>
    ''' <param name="depth">Depth string</param>
    ''' <param name="parm">Parameter name</param>
    ''' <returns>True if successful</returns>
    Private Function TryGetEfdcDepth(index As Integer, ByRef depth As String, ByRef parm As String) As Boolean
        Return TryGetEfdcDepth(chkParmsSim.Items(index).ToString, depth, parm)
    End Function

    ''' <summary>
    ''' Given item in parameter chklistbox, parse parameter and return depth and parameter name value if possible
    ''' Note: if depth cannot be parsed, will still return full parameter name
    ''' </summary>
    ''' <param name="name">bmd parameter name</param>
    ''' <param name="depth">Depth string</param>
    ''' <param name="parm">Parameter name</param>
    ''' <returns>True if successful</returns>
    Private Function TryGetEfdcDepth(name As String, ByRef depth As String, ByRef parm As String) As Boolean
        If name.StartsWith("Bot") And name.Length > 4 Then
            depth = name.Substring(0, 3)
            parm = name.Substring(4)
            Return True
        End If
        If name.StartsWith("K=") And name.Length > 5 Then
            depth = name.Substring(0, 4)
            parm = name.Substring(5)
            Return True
        End If
        If name.StartsWith("Surf ") And name.Length > 5 Then
            depth = name.Substring(0, 4)
            parm = name.Substring(5)
            Return True
        End If
        If name.StartsWith("layer K=") And name.Length > 11 Then
            depth = name.Substring(0, 10)
            parm = name.Substring(11)
            Return True
        End If

        depth = DEPTH_AVERAGED
        parm = name
        Return True
    End Function

    ''' <summary>
    ''' Given item in stations chklistbox, parse station and return i,j values if possible
    ''' </summary>
    ''' <param name="index">Index value</param>
    ''' <param name="i">Parsed i value</param>
    ''' <param name="j">Parsed j value</param>
    ''' <returns>True if successful</returns>
    ''' <remarks></remarks>
    Private Function TryGetEfdcIJ(index As Integer, ByRef i As Integer, ByRef j As Integer) As Boolean
        Return TryGetEfdcIJ(chkStationsSim.Items(index).ToString, i, j)
    End Function

    ''' <summary>
    ''' Given name of station, parse and return i,j values if possible
    ''' </summary>
    ''' <param name="name">Station Name</param>
    ''' <param name="i">Parsed i value</param>
    ''' <param name="j">Parsed j value</param>
    ''' <returns>True if successful</returns>
    ''' <remarks></remarks>
    Private Function TryGetEfdcIJ(name As String, ByRef i As Integer, ByRef j As Integer) As Boolean
        If name.Contains("I=") And name.Contains("J=") And name.Length >= 11 Then
            'format is "I=XXX J=XXX"
            Dim s1 As String = name.Substring(2, 3)
            Dim s2 As String = name.Substring(8, 3)
            If IsNumeric(s1) And IsNumeric(s2) Then
                i = Val(s1)
                j = Val(s2)
                Return True
            End If
        End If
        Return False
    End Function

    ''' <summary>
    ''' Given item in stations chklistbox, parse station and return i,j values if possible
    ''' </summary>
    ''' <param name="index">Index value</param>
    ''' <param name="i">Parsed i value</param>
    ''' <param name="j">Parsed j value</param>
    ''' <returns>True if successful</returns>
    ''' <remarks></remarks>
    Private Function TryGetWaspIJK(index As Integer, ByRef i As Integer, ByRef j As Integer, ByRef k As Integer) As Boolean
        Return TryGetWaspIJK(chkStationsSim.Items(index).ToString, i, j, k)
    End Function

    ''' <summary>
    ''' Given name of station, parse and return i,j values if possible
    ''' </summary>
    ''' <param name="name">Station Name</param>
    ''' <param name="i">Parsed i value</param>
    ''' <param name="j">Parsed j value</param>
    ''' <returns>True if successful</returns>
    ''' <remarks></remarks>
    Private Function TryGetWaspIJK(name As String, ByRef i As Integer, ByRef j As Integer, ByRef k As Integer) As Boolean
        If name.Contains("I=") And name.Contains("J=") And name.Contains("K=") Then
            'format is "I=XXXJ=XXXK=XXX - Nd 3" (but not fixed format)
            name = StringSplit(name, " - ")(0)
            Dim ar() As String = name.Split("=")
            If ar.Length >= 4 Then
                Dim s1 As String = ar(1).Replace("J", "")
                Dim s2 As String = ar(2).Replace("K", "")
                Dim s3 As String = ar(3)
                If IsNumeric(s1) And IsNumeric(s2) And IsNumeric(s3) Then
                    i = Val(s1)
                    j = Val(s2)
                    k = Val(s3)
                    Return True
                End If
            End If
        End If
        Return False
    End Function

    Private Function TryGetEfdcParmIndex(depth As String, parm As String, ByRef index As Integer) As Boolean
        Dim name As String = ""
        If TryGetEfdcParmName(depth, parm, name) Then
            index = chkParmsSim.Items.IndexOf(name)
            Return True
        End If
        Return False
    End Function

    Private Function TryGetEfdcParmName(depth As String, parm As String, ByRef name As String) As Boolean
        For ii As Integer = 0 To chkParmsSim.Items.Count - 1
            Dim s As String = chkParmsSim.Items(ii)
            If s = String.Format("{0} {1}", depth, parm) Or depth = DEPTH_AVERAGED And s = parm Then
                name = s
                Return True
            End If
        Next
        Return False
    End Function

    ''' <summary>
    ''' Given desired i,j values, return index of matching station in chklistbox
    ''' </summary>
    ''' <param name="i">I value</param>
    ''' <param name="j">J value</param>
    ''' <param name="index">Item index</param>
    ''' <returns>True if successful</returns>
    Private Function TryGetEfdcStationIndex(i As Integer, j As Integer, ByRef index As Integer) As Boolean
        For ii As Integer = 0 To chkStationsSim.Items.Count - 1
            Dim s As String = chkStationsSim.Items(ii)
            If s.StartsWith(String.Format("I={0,3} J={1,3}", i, j)) Then
                index = ii
                Return True
            End If
        Next
        Return False
    End Function

    ''' <summary>
    ''' Given desired i,j values, return string of matching station in chklistbox
    ''' </summary>
    ''' <param name="i">I value</param>
    ''' <param name="j">J value</param>
    ''' <param name="name">Station name</param>
    ''' <returns>True if successful</returns>
    Private Function TryGetEfdcStationName(i As Integer, j As Integer, ByRef name As String) As Boolean
        Dim index As Integer
        If TryGetEfdcStationIndex(i, j, index) Then
            name = chkStationsSim.Items(index)
            Return True
        Else
            Return False
        End If
    End Function

    Private Function TryGetWaspParmIndex(parm As String, ByRef index As Integer) As Boolean
        index = chkParmsSim.Items.IndexOf(parm)
        Return index <> -1
    End Function

    Private Function TryGetWaspParmName(parm As String, ByRef name As String) As Boolean
        name = parm
        Return True
    End Function

    ''' <summary>
    ''' Given desired i,j values, return index of matching station in chklistbox
    ''' </summary>
    ''' <param name="i">I value</param>
    ''' <param name="j">J value</param>
    ''' <param name="k">K value</param>
    ''' <param name="index">Item index</param>
    ''' <returns>True if successful</returns>
    Private Function TryGetWaspStationIndex(i As Integer, j As Integer, k As Integer, ByRef index As Integer) As Boolean
        For ii As Integer = 0 To chkStationsSim.Items.Count - 1
            Dim s As String = chkStationsSim.Items(ii)
            Dim iii, jjj, kkk As Integer
            If TryGetWaspIJK(s, iii, jjj, kkk) AndAlso iii = i AndAlso jjj = j AndAlso kkk = k Then
                index = ii
                Return True
            End If
        Next
        Return False
    End Function

    ''' <summary>
    ''' Given desired i,j values, return string of matching station in chklistbox
    ''' </summary>
    ''' <param name="i">I value</param>
    ''' <param name="j">J value</param>
    ''' <param name="name">Station name</param>
    ''' <returns>True if successful</returns>
    Private Function TryGetWaspStationName(i As Integer, j As Integer, k As Integer, ByRef name As String) As Boolean
        Dim index As Integer
        If TryGetWaspStationIndex(i, j, k, index) Then
            name = chkStationsSim.Items(index)
            Return True
        Else
            Return False
        End If
    End Function

#End Region

#Region "Utility routines..."

    ''' <summary>
    ''' Return currently selected branch
    ''' </summary>
    Private Function ActiveBranch() As clsBranch
        If cboBranch.SelectedIndex = -1 Then Return Nothing
        Return Calibration.dictBranches(cboBranch.Text)
    End Function

    ''' <summary>
    ''' Return currently selected station
    ''' </summary>
    Private Function ActiveStation() As clsStation
        If ActiveBranch() Is Nothing OrElse lstStationsAgg.SelectedIndex = -1 Then Return Nothing
        Return ActiveBranch.dictStations(lstStationsAgg.Text)
    End Function

    ''' <summary>
    ''' Return currently selected parameter
    ''' </summary>
    Private Function ActiveParameter() As clsParameter
        If ActiveBranch() Is Nothing OrElse ActiveStation() Is Nothing OrElse lstParmsAgg.SelectedIndex = -1 Then Return Nothing
        Return ActiveStation.dictParameters(lstParmsAgg.Text)
    End Function

    Private Sub FillStationList()
        If cboBranch.SelectedIndex = -1 Then Exit Sub
        lstStationsAgg.Items.Clear()
        For Each s As String In ActiveBranch.dictStations.Keys
            lstStationsAgg.Items.Add(s)
        Next
        lstStationsAgg.SelectedIndex = IIf(lstStationsAgg.Items.Count = 0, -1, 0)
    End Sub

    Private Sub SaveChecklists()
        If ActiveParameter() Is Nothing Then Exit Sub
        With ActiveParameter()
            SaveChecklist(chkStationsMeas, .lstStationsMeas)
            SaveChecklist(chkParmsMeas, .lstParametersMeas)
            If IsEfdc Then
                .lstParametersSim.Clear()
                For Each depth As String In chkEFDCDepth.CheckedItems
                    For Each parm As String In chkEFDCParms.CheckedItems
                        Dim name As String = ""
                        If TryGetEfdcParmName(depth, parm, name) Then
                            .lstParametersSim.Add(name)
                        End If
                    Next
                Next
            ElseIf IsWasp Then
                .lstParametersSim.Clear()
                For Each parm As String In chkEFDCParms.CheckedItems
                    .lstParametersSim.Add(parm)
                Next
            Else
                SaveChecklist(chkStationsSim, .lstStationsSim)
                SaveChecklist(chkParmsSim, .lstParametersSim)
            End If
        End With
        UpdateLabels()
    End Sub

    Private Sub SaveChecklist(chk As CheckedListBox, ByRef lst As Generic.List(Of String))
        With lst
            .Clear()
            For Each s As String In chk.CheckedItems
                If chk Is chkStationsMeas Or chk Is chkStationsSim Then 'stations are formatted like Station_ID - Station_Name
                    .Add(StringSplit(s, " - ")(0))
                Else
                    .Add(s)
                End If
            Next
        End With
    End Sub

    ''' <summary>
    ''' Update all checklistboxes to reflect current agg parameter
    ''' </summary>
    Private Sub UpdateChecklists()
        For i As Integer = 1 To 2
            Dim chk As CheckedListBox = Choose(i, chkStationsMeas, chkParmsMeas)
            If ActiveParameter() Is Nothing Then
                ClearCheckboxes(chk)
            Else
                With ActiveParameter()
                    Dim lst As Generic.List(Of String) = Choose(i, .lstStationsMeas, .lstParametersMeas)
                    For j As Integer = 0 To chk.Items.Count - 1
                        Dim s As String = chk.Items(j)
                        If i = 1 Then s = StringSplit(s, " - ")(0) 'station lists have name appended
                        chk.SetItemChecked(j, lst.Contains(s))
                    Next
                End With
            End If
            chk.ClearSelected()
        Next

        If IsEfdc Then
            UpdateEfdcChecklists()
        ElseIf IsWasp Then
            UpdateWaspChecklists()
        Else
            For i As Integer = 1 To 2
                Dim chk As CheckedListBox = Choose(i, chkStationsSim, chkParmsSim)
                If ActiveParameter() Is Nothing Then
                    ClearCheckboxes(chk)
                Else
                    With ActiveParameter()
                        Dim lst As Generic.List(Of String) = Choose(i, .lstStationsSim, .lstParametersSim)
                        For j As Integer = 0 To chk.Items.Count - 1
                            Dim s As String = chk.Items(j)
                            If i = 1 Then s = StringSplit(s, " - ")(0) 'station lists have name appended
                            chk.SetItemChecked(j, lst.Contains(s))
                        Next
                    End With
                End If
                chk.ClearSelected()
            Next
        End If
    End Sub

    ''' <summary>
    ''' Update all EFDC checklistboxes to reflect current agg parameter
    ''' </summary>
    Private Sub UpdateEfdcChecklists()
        If ActiveParameter() Is Nothing Then
            cboEFDCMinI.SelectedIndex = -1
            cboEFDCMaxI.SelectedIndex = -1
            cboEFDCMinJ.SelectedIndex = -1
            cboEFDCMaxJ.SelectedIndex = -1
            ClearCheckboxes(chkEFDCDepth)
            ClearCheckboxes(chkEFDCParms)
        Else
            With ActiveParameter()
                Dim imin As Integer = Integer.MaxValue, imax As Integer = Integer.MinValue
                Dim jmin As Integer = Integer.MaxValue, jmax As Integer = Integer.MinValue
                For Each Name As String In .lstStationsSim
                    Dim i As Integer = 0, j As Integer = 0
                    If TryGetEfdcIJ(Name, i, j) Then
                        imin = Math.Min(imin, i)
                        imax = Math.Max(imax, i)
                        jmin = Math.Min(jmin, j)
                        jmax = Math.Max(jmax, j)
                    End If
                Next
                If imin = Integer.MaxValue Then 'none found
                    cboEFDCMinI.SelectedIndex = -1
                    cboEFDCMaxI.SelectedIndex = -1
                    cboEFDCMinJ.SelectedIndex = -1
                    cboEFDCMaxJ.SelectedIndex = -1
                Else
                    cboEFDCMinI.Text = imin
                    cboEFDCMaxI.Text = imax
                    cboEFDCMinJ.Text = jmin
                    cboEFDCMaxJ.Text = jmax
                End If

                ClearCheckboxes(chkEFDCDepth)
                ClearCheckboxes(chkEFDCParms)

                For Each Name As String In .lstParametersSim
                    Dim depth As String = "", parm As String = ""
                    If TryGetEfdcDepth(Name, depth, parm) Then
                        With chkEFDCDepth
                            For i As Integer = 0 To .Items.Count - 1
                                If .Items(i) = depth Then .SetItemChecked(i, True)
                            Next
                        End With
                        With chkEFDCParms
                            For i As Integer = 0 To .Items.Count - 1
                                If .Items(i) = parm Then .SetItemChecked(i, True)
                            Next
                        End With
                    End If
                Next
            End With
        End If
    End Sub

    ''' <summary>
    ''' Update all EFDC checklistboxes to reflect current agg parameter
    ''' </summary>
    Private Sub UpdateWaspChecklists()
        If ActiveParameter() Is Nothing Then
            cboEFDCMinI.Items.Clear()
            cboEFDCMaxI.Items.Clear()
            cboEFDCMinJ.Items.Clear()
            cboEFDCMaxJ.Items.Clear()
            ClearCheckboxes(chkEFDCDepth)
            ClearCheckboxes(chkEFDCParms)
        Else
            ClearCheckboxes(chkEFDCDepth)
            With ActiveParameter()
                Dim imin As Integer = Integer.MaxValue, imax As Integer = Integer.MinValue
                Dim jmin As Integer = Integer.MaxValue, jmax As Integer = Integer.MinValue
                For Each Name As String In .lstStationsSim
                    Dim i As Integer = 0, j As Integer = 0, k As Integer = 0
                    If TryGetWaspIJK(Name, i, j, k) Then
                        imin = Math.Min(imin, i)
                        imax = Math.Max(imax, i)
                        jmin = Math.Min(jmin, j)
                        jmax = Math.Max(jmax, j)
                        With chkEFDCDepth
                            For ii As Integer = 0 To .Items.Count - 1
                                If .Items(ii) = "K=" & k Then .SetItemChecked(ii, True)
                            Next
                        End With
                    End If
                Next
                If imin = Integer.MaxValue Then 'none found
                    cboEFDCMinI.SelectedIndex = -1
                    cboEFDCMaxI.SelectedIndex = -1
                    cboEFDCMinJ.SelectedIndex = -1
                    cboEFDCMaxJ.SelectedIndex = -1
                Else
                    cboEFDCMinI.Text = imin
                    cboEFDCMaxI.Text = imax
                    cboEFDCMinJ.Text = jmin
                    cboEFDCMaxJ.Text = jmax
                End If

                ClearCheckboxes(chkEFDCParms)

                For Each Name As String In .lstParametersSim
                    With chkEFDCParms
                        For i As Integer = 0 To .Items.Count - 1
                            If .Items(i) = Name Then .SetItemChecked(i, True)
                        Next
                    End With
                Next
            End With
        End If
    End Sub

    ''' <summary>
    ''' Clear all checks in checkedlistbox
    ''' </summary>
    ''' <param name="chk">Checkedlistbox to clear</param>
    Private Sub ClearCheckboxes(chk As CheckedListBox)
        With chk
            For i As Integer = 0 To .Items.Count - 1
                .SetItemChecked(i, False)
            Next
        End With
    End Sub

    ''' <summary>
    ''' Update labels on form that show how many list items are checked
    ''' </summary>
    Private Sub UpdateLabels()
        If ActiveParameter() Is Nothing Then Exit Sub
        For i As Integer = 1 To 4
            Dim lbl As System.Windows.Forms.Label = Choose(i, lblStaMeas, lblParmMeas, lblStaSim, lblParmSim)
            Dim chk As CheckedListBox = Choose(i, chkStationsMeas, chkParmsMeas, chkStationsSim, chkParmsSim)
            lbl.Text = String.Format(IIf(i Mod 2 = 0, "Parameters", "Stations") & " ({0} of {1} checked)", chk.CheckedItems.Count, chk.Items.Count)
        Next
        lblEFDCNum.Text = String.Format("Selected Cells: {0}/{1}; Parms: {2}/{3}", ActiveParameter.lstStationsSim.Count, chkStationsSim.Items.Count, ActiveParameter.lstParametersSim.Count, chkParmsSim.Items.Count)
    End Sub
#End Region

    Private Sub dtMinDate_Validated(sender As Object, e As System.EventArgs) Handles dtMinDate.Validated
        Calibration.MinDate = dtMinDate.Value
    End Sub

    Private Sub dtMaxDate_Validated(sender As Object, e As System.EventArgs) Handles dtMaxDate.Validated
        Calibration.MaxDate = dtMaxDate.Value
    End Sub

    Private Sub txtMinDepth_Validated(sender As Object, e As System.EventArgs) Handles txtMinDepth.Validated
        If ActiveParameter() IsNot Nothing Then ActiveParameter.MinDepth = IIf(IsNumeric(txtMinDepth.Text), Val(txtMinDepth.Text), Double.MinValue)
    End Sub

    Private Sub txtMaxDepth_Validated(sender As Object, e As System.EventArgs) Handles txtMaxDepth.Validated
        If ActiveParameter() IsNot Nothing Then ActiveParameter.MaxDepth = IIf(IsNumeric(txtMaxDepth.Text), Val(txtMaxDepth.Text), Double.MaxValue)
    End Sub

    Private Sub btnStationsAgg_Click(sender As System.Object, e As System.EventArgs) Handles btnStationsAgg.Click
        NewStation()
    End Sub

    Private Sub btnParmsAgg_Click(sender As System.Object, e As System.EventArgs) Handles btnParmsAgg.Click
        mnuNewParm.PerformClick()
    End Sub
End Class